package com.gosophia.commons.persistence;

import java.io.Serializable;
import java.lang.reflect.ParameterizedType;
import java.util.List;
import java.util.Map;

import javax.annotation.PostConstruct;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;

import com.gosophia.commons.OrderCondition;
import com.gosophia.commons.Page;
import com.gosophia.commons.PropertyFilter;
import com.gosophia.commons.exception.BusinessException;

/**
 * 所有DAO的基类
 * 注：需要在自己的工程Spring配置moduleContext文件中注入entityRepository
 * 使用方法如下：
 * {@code <bean id="entityRepository" class="com.gosophia.commons.persistence.HibernateRepository" scope="prototype"/> } 
 * @author wangxinbing
 * @since 2010.09.01
 */
public class BaseDao<T, PK extends Serializable> {

    @Autowired
    @Qualifier("entityRepository")
    private EntityRepository<T, PK> entityRepository;

    /**
     * 保存需要更新的实体对象，如果不存在该记录就新增一条
     * 
     * @param entity
     *            需要更新的实体
     * */
    public void update(final T entity) {
        entityRepository.update(entity);
        this.flush();
    }

    /**
     * 
     * 更新实体指定的几个属性
     * 
     * @param id
     *            主键
     * @param version
     *            版本号
     * @param updatedParams
     *            要更新属性的键值对
     * @return 更新记录数
     */
    public void update(PK id, Long version, Map<String, Object> updatedParams) {
        entityRepository.update(id, version, updatedParams);
        this.flush();
    }

    /**
     * 保存需要新创建的实体对象
     * 
     * @param entity
     */
    public void save(T entity) {
    	entityRepository.save(entity);
        this.flush();
    }
    
    public Serializable add(T entity) {
    	Serializable rslt = entityRepository.add(entity);
        this.flush();
        return rslt;
    }

    /**
     * 删除对象
     * 
     * @param entity
     */
    public void delete(T entity) {
        entityRepository.delete(entity);
        this.flush();
    }

    /**
     * 按id删除对象
     * 
     * @param id
     */
    public void delete(PK id) {
        entityRepository.delete(id);
        this.flush();
    }

    /**
     * 删除实体
     * 
     * @param id
     *            实体Id
     * @param version
     *            实体版本号
     * @return int 返回删除的条数
     */
    public void delete(final PK id, Long version) {
        entityRepository.delete(id, version);
        this.flush();
    }

    /**
     * 获取全部对象,支持排序.
     * 
     * @param orderConditions
     *            属性的排序条件
     * @return List
     */
    public List<T> getAllByOrder(List<OrderCondition> orderConditons) {
        return entityRepository.getAllByOrder(orderConditons);
    }

    /**
     * 按属性查找对象列表,匹配方式为相等.
     * 
     * @param propertyName
     *            属性名称
     * @param value
     *            属性值
     * @return List
     */
    public List<T> getByProperty(final String propertyName, final Object value) {
        return entityRepository.findByProperty(propertyName, value);
    }

    /**
     * 根据一组属性查找对象列表
     * 
     * @param properties
     *            属性名称、属性值映射map
     * @return List
     */
    public List<T> getByProperties(Map<String, Object> properties) {
        return entityRepository.findByProperties(properties);
    }

    /**
     * 按属性查找唯一对象,匹配方式为相等
     * 
     * @param propertyName
     * @param value
     * @return T
     */
    public T getUniqueByProperty(final String propertyName, final Object value) {
        return entityRepository.findUniqueByProperty(propertyName, value);
    }

    /**
     * 分页获取对象
     * 
     * @param page
     * @return Page
     */
    public Page<T> getPage(Page<T> page, OrderCondition... orderConditions) {
        return entityRepository.findPage(page,orderConditions);
    }
    
    /**
     * 分页获取对象
     * 
     * @param page
     * @return Page
     */
    public Page<T> getPage(Page<T> page, List<OrderCondition> orderConditions) {
        return entityRepository.findPage(page,orderConditions);
    }

    /**
     * 按属性过滤条件列表分页查找对象
     * 
     * @param page
     * @param propertyFilters
     * @return Page
     */
    public Page<T> getPageByProperties(final Page<T> page,
            final List<PropertyFilter> propertyFilters) {
        return entityRepository.findPageByProperties(page, propertyFilters);
    }

    /**
     * 返回根据属性过滤条件过滤、排序后的Page对象
     * 
     * @param page
     *            数据分页对象
     * @param propertyFilters
     *            属性过滤列表，包含属性名称，属性值，属性操作符
     * @param orderConditions
     *            排序条件
     *            ，包含排序依据属性的名称，排序顺序（升序，或降序），例如按照"name"升序排序:OrderCondition.asc
     *            ("name")
     * @return Page
     * */
    public Page<T> getPageByProperties(Page<T> page, List<PropertyFilter> propertyFilters,
            List<OrderCondition> orderConditions) {
        return entityRepository.findPageByProperties(page, propertyFilters,
                orderConditions);
    }
    
    /**
     * 返回根据属性过滤条件过滤、排序后的Page对象
     * 
     * @param page
     *            数据分页对象
     * @param propertyFilters
     *            属性过滤列表，包含属性名称，属性值，属性操作符
     * @param orderConditions
     *            排序条件
     *            ，包含排序依据属性的名称，排序顺序（升序，或降序），例如按照"name"升序排序:OrderCondition.asc
     *            ("name")
     * @return Page
     * */
    public Page<T> getPageByProperties(Page<T> page, List<PropertyFilter> propertyFilters, 
            OrderCondition... orderConditions) {
        return entityRepository.findPageByProperties(page, propertyFilters, orderConditions);
    }

    /**
     * 按id列表获取实体对象列表
     * 
     * @param ids
     * @return List
     */
    public List<T> getByIds(List<PK> ids) {
        return entityRepository.findByIds(ids);
    }

    /**
     * 按id获取实体对象
     * 
     * @param id
     * @return T
     */
    public T get(PK id) {
        return entityRepository.get(id);
    }

    /**
     * 获取全部实体对象列表
     * 
     * @return List
     */
    public List<T> getAll() {
        return entityRepository.getAll();
    }
    
    /**
     * 全字段模糊分页搜索，搜索范围为实体上标注了@ShowItem或者@SearchEnable标注的属性
     * @param page
     * @param searchStr  模糊查询条件
     * @param dateFormat 模糊查询中日期显示格式（yyyy-mm-dd 或 其它）
     * @param orderConditions 排序条件
     * @return 
     * @throws BusinessException 没有指定模糊查询匹配列
     */
    public Page<T> getPageBySimpleSearching(Page<T> page, String searchStr, String dateFormat,
            OrderCondition... orderConditions){
        return entityRepository.allFiledSearching(page, searchStr,dateFormat, orderConditions);
    }
	/**
	 * 全字段模糊搜索，搜索范围为实体上标注了@ShowItem标注的属性
	 * 
	 * @throws BusinessException
	 *             当没有指定模糊匹配列时，抛出异常
	 * */
	@Deprecated
	public Page<T> getPageBySimpleSearching(Page<T> page, String searchStr,
			String orderbyStr, String orderbyFlg) {
		return entityRepository.allFiledSearching(page, searchStr, orderbyStr,
				orderbyFlg);
	}
	
	/**
     * 全字段模糊分页搜索，搜索范围为实体上标注了@SearchEnable或JoinSearchItem标注的属性
     * @param page
     * @param searchStr  模糊查询条件
     * @param orderConditions 排序条件
     * @return
     * @throws BusinessException 没有指定模糊查询匹配列
     */
    public Page<T> getPageBySimpleSearching(Page<T> page, String searchStr,
            OrderCondition... orderConditions){
        return entityRepository.allFiledSearching(page, searchStr, orderConditions);
    }
    
    /**
     * 全字段模糊分页搜索，搜索范围为实体上标注了@ShowItem或者@SearchEnable标注的属性
     * @param page
     * @param searchStr  模糊查询条件
     * @param dateFormat 模糊查询中日期显示格式（yyyy-mm-dd 或 其它）
     * @param orderConditions 排序条件
     * @return
     * @throws BusinessException 没有指定模糊查询匹配列
     */
    public Page<T> getPageBySimpleSearching(Page<T> page, String searchStr, String dateFormat,
            List<PropertyFilter> propertyFilters, List<OrderCondition> orderConditions){
        return entityRepository.allFiledSearching(page, searchStr,dateFormat, propertyFilters, orderConditions);
    }
    
    /**
     * 全字段模糊分页搜索，搜索范围为实体上标注了@ShowItem或者@SearchEnable标注的属性
     * @param page
     * @param searchStr  模糊查询条件
     * @param dateFormat 模糊查询中日期显示格式（yyyy-mm-dd 或 其它）
     * @param orderConditions 排序条件
     * @return
     * @throws BusinessException 没有指定模糊查询匹配列
     */
    public Page<T> getPageBySimpleSearching(Page<T> page, String searchStr, String dateFormat,
            List<OrderCondition> orderConditions){
        return entityRepository.allFiledSearching(page, searchStr,dateFormat, orderConditions);
    }
    
    /**
     * 全字段模糊分页搜索，搜索范围为实体上标注了@ShowItem或者@SearchEnable标注的属性
     * @param page
     * @param searchStr  模糊查询条件
     * @param orderConditions 排序条件
     * @return
     * @throws BusinessException 没有指定模糊查询匹配列
     */
    public Page<T> getPageBySimpleSearching(Page<T> page, String searchStr,
            List<OrderCondition> orderConditions){
        return entityRepository.allFiledSearching(page, searchStr, orderConditions);
    }

    /**
     * 刷新
     */
    public void flush() {
        entityRepository.flush();
    }

    /**
     * 根据namedQuery形式查询记录数，形式为 name :value
     * 
     * @param queryName
     * @param values
     * @return
     */
    public long countNamedQueryResult(final String queryName,
            final Map<String, Object> values) {
        return entityRepository.countNamedQueryResult(queryName, values);
    }

    /**
     * 根据namedQuery形式查询记录数，形式参照 property =?
     * 
     * @param queryName
     * @param values
     * @return
     */
    public long countNamedQueryResult(final String queryName,
            final Object... values) {
        return entityRepository.countNamedQueryResult(queryName, values);
    }

    /**
     * 执行没有返回值的NamedQuery
     * 
     * @param queryName
     *            名称
     * @param values
     *            参数集合
     */
    public void executeNamedQuery(String queryName, Object... values) {
        entityRepository.executeNamedQuery(queryName, values);
    }

    /**
     * 执行没有返回值的NamedQuery
     * 
     * @param queryName
     *            名称
     * @param values
     *            参数集合
     */
    public void executeNamedQuery(String queryName, Map<String, Object> values) {
        entityRepository.executeNamedQuery(queryName, values);
    }

    /**
     * 根据 namedQuery的名称 进行查询
     * 
     * @param queryName
     *            命名查询
     * @param values
     *            命名查询的参数值 ，参数可以为0或多个
     * 
     * 
     * @see com.gosophia.commons.Repository#find(java.lang.String,
     *      java.util.Map)
     */
    public <X> List<X> getListByNamedQuery(String queryName, Object... values) {
        return entityRepository.findListByNamedQuery(queryName, values);
    }

    /**
     * 根据namedQuery 进行查询
     * 
     * @param queryName
     *            已定义的namedQuery名称
     * @param value
     *            命名查询的参数 Map集合
     * @see com.gosophia.commons.Repository#find(java.lang.String,
     *      java.util.Map)
     */
    public <X> List<X> getListByNamedQuery(String queryName,
            Map<String, Object> values) {
        return entityRepository.findListByNamedQuery(queryName, values);
    }

    /**
     * 使用hql进行分页查询，使用单一参数
     * 
     * @param page
     *            分页查询对象 ，封装了分页查询参数
     * @param hql
     *            HQl查询字符串，推荐使用具名参数查询，hql格式举例：from ClassName where propertyName1
     *            =:propertyName1 and propertyName2 =:propertyName2
     * @param parame
     *            参数名称
     * @param values
     *            参数值
     * @return
     */
    public Page<T> getPageByNamedQuery(Page<T> page, String queryName,
            Object... values) {
        return entityRepository.findPageByNamedQuery(page, queryName, values);
    }

    /**
     * 使用命名查询的方式进行分页查询
     * 
     * @param page
     *            分页查询对象 封装了分页参数设定
     * @param queryName
     *            已定义命名查询名称
     * @param values
     *            参数值
     * @return
     */
    public Page<T> getPageByNamedQuery(Page<T> page, String queryName,
            Map<String, Object> values) {
        return entityRepository.findPageByNamedQuery(page, queryName, values);
    }
    
    public Page<T> getPageByNamedQuery(Page<T> page, String queryName, List<OrderCondition> orderConditions, 
            Object... values) {
        return entityRepository.findPageByNamedQuery(page, queryName, orderConditions, values);
    }

    public Page<T> getPageByNamedQuery(Page<T> page, String queryName, Map<String, Object> values, 
            OrderCondition... orderConditions) {
        return entityRepository.findPageByNamedQuery(page, queryName, values, orderConditions);
    }

    public Page<T> getPageByNamedQuery(Page<T> page, String queryName, Map<String, Object> values, 
            List<OrderCondition> orderConditions) {
        return entityRepository.findPageByNamedQuery(page, queryName, values, orderConditions);
    }
    
    //王新兵 2010-12-01
    /**
     * 使用Hql进行分页查询
     * 
     * @param page
     *            分页查询对象 ，封装了分页查询参数
     * @param hql
     *            HQl查询字符串,hql格式为
     * @param values
     *            hql查询参数值，需要参照hql中的参数顺序
     * @return
     */
    public Page<T> getPageByHql(final Page<T> page, final String hql, final Object... values){
        return entityRepository.findPageByHql(page, hql, values);
    }
    //王新兵 2010-12-01
    /**
     * 使用Hql进行分页查询
     * 
     * @param page
     *            分页查询对象 ，封装了分页查询参数
     * @param hql
     *            HQl查询字符串,hql 格式为：from ClassName where propertyName1
     *            =:propertyName1 and propertyName2 =:propertyName2
     * @param values
     *            hql查询参数值
     * @return
     */
    public Page<T> getPageByHql(final Page<T> page, final String hql,
            final Map<String, Object> values){
        return entityRepository.findPageByHql(page, hql, values);
    }

    /**
     * 根据namedQuery 名称 查询唯一的实体
     * 
     * @param queryName
     *            命名查询的名称
     *@param values
     *            命名查询参数，参数可为0或多个
     * @see com.gosophia.commons.Repository#findUnique(java.lang.String,
     *      java.util.Map)
     */
    public T getUniqueByNamedQuery(final String queryName,
            final Object... values) {
        return entityRepository.findUniqueByNamedQuery(queryName, values);
    }

    /**
     * 根据命名查询唯一的对象
     * 
     * @param queryName
     *            已定以命名查询的名称
     * @param values
     *            命名查询的参数
     * @see com.gosophia.commons.Repository#findUnique(java.lang.String,
     *      java.util.Map)
     */
    public T getUniqueByNamedQuery(final String queryName,
            final Map<String, Object> values) {
        return entityRepository.findUniqueByNamedQuery(queryName, values);
    }
    
    /**
     * 使用hql查询唯一的数据项
     * 
     * @see com.gosophia.commons.Repository#findUnique(java.lang.String,
     *      java.lang.Object)
     */
    public <X> X getUniqueByHql(final String hql, final Object... values){
        return entityRepository.findUniqueByHql(hql, values);
    }

    /**
     * 清除Session中指定实体
     * 
     * @param entity
     */
    public void clearEntityOnSession(T entity) {
        entityRepository.clearEntityOnSession(entity);
    }
    
    /**
     *清除Session
     */
    public void clearSession(){
    	entityRepository.clearSession();
    }
    
    /** 根据属性,排序条件查询,返回列表    wangxinbing 11.03.03*/
    /**
     * 根据属性,排序条件查询,返回列表
     * @param propertyFilters
     * @param orderConditions
     * @return 
     */
    public List<T> getListByProperties(List<PropertyFilter> propertyFilters,
            OrderCondition... orderConditions){
        return entityRepository.findListByProperties(propertyFilters, orderConditions);
    }
    /**
     * 根据属性,排序条件查询,返回列表
     * @param propertyFilters
     * @param orderConditions
     * @return
     */
    public List<T> getListByProperties(List<PropertyFilter> propertyFilters,
            List<OrderCondition> orderConditions){
        return entityRepository.findListByProperties(propertyFilters, orderConditions);
    }
    /**
     * 根据属性,排序条件查询,返回列表
     * @param propertyFilters
     * @return
     */
    public List<T> getListByProperties(List<PropertyFilter> propertyFilters){
        return entityRepository.findListByProperties(propertyFilters);
    }

    // Spring在所有属性注入后自动执行的函数.
    @SuppressWarnings("unchecked")
    @PostConstruct
    protected void initEntityClass() {
        Class<T> entityClass = (Class<T>) ((ParameterizedType) getClass()
                .getGenericSuperclass()).getActualTypeArguments()[0];
        String entityClassSimpleName = entityClass.getSimpleName();

        entityRepository.setEntityClassInfo(entityClass, entityClassSimpleName);
    }
}
